
package com.joysuch.wwyt.bp.service.impl;

import com.alibaba.fastjson.JSON;
import com.joysuch.wwyt.bp.bean.BpTypeBean;
import com.joysuch.wwyt.bp.bean.facility.BpProductionFacilityTypeBean;
import com.joysuch.wwyt.bp.bean.facility.BpProductionFacilityTypeDto;
import com.joysuch.wwyt.bp.entity.BpDepart;
import com.joysuch.wwyt.bp.entity.BpProductionFacility;
import com.joysuch.wwyt.bp.entity.BpProductionFacilityType;
import com.joysuch.wwyt.bp.repository.BpDepartDao;
import com.joysuch.wwyt.bp.repository.BpProductionFacilityDao;
import com.joysuch.wwyt.bp.repository.BpProductionFacilityTypeDao;
import com.joysuch.wwyt.bp.service.BpProductionFacilityService;
import com.joysuch.wwyt.bp.service.BpProductionFacilityTypeService;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.edu.bean.EduCertEditUserNameBean;
import com.joysuch.wwyt.edu.enums.CertificateRemindTypes;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.util.Assert;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class BpProductionFacilityTypeServiceImpl implements BpProductionFacilityTypeService {

    @Autowired
    private BpProductionFacilityTypeDao dao;
    @Autowired
    private BpProductionFacilityDao facilityDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private BpDepartDao bpDepartDao;
    @Autowired
    private BpProductionFacilityService facilityService;

    @Override
    public List<BpProductionFacilityType> list() {
        List<BpProductionFacilityType> list = dao.findAll();
        for (BpProductionFacilityType type : list) {
            List<BpProductionFacility> tempList = facilityDao.findByType(type.getId());
            type.setNumber(tempList.size());
        }
        return list;
    }

    @Override
    public List<BpProductionFacilityTypeDto> tree() {
        List<BpProductionFacilityType> list = dao.findAll();
        List<BpProductionFacilityTypeDto> result = convert(list);

        Map<Long, BpProductionFacilityTypeDto> map = result.stream()
                .collect(Collectors.toMap(BpProductionFacilityTypeDto::getId, Function.identity()));
        for (BpProductionFacilityTypeDto bpInvestigateStore : result) {
            Long parentId = bpInvestigateStore.getParentId();
            if (parentId != null && parentId != 0) {
                BpProductionFacilityTypeDto temp = map.get(parentId);
                if (temp != null) {
                    temp.getChildrenSet().add(bpInvestigateStore);
                }
            }
        }
        List<BpProductionFacilityTypeDto> collect = result.stream().filter(r -> r.getParentId() != null && r.getParentId() == 0)
                .collect(Collectors.toList());
        return collect;
    }

    private List<BpProductionFacilityTypeDto> convert(List<BpProductionFacilityType> list) {
        return list.stream().map(e -> {
            BpProductionFacilityTypeDto dto = convertType(e);
            return dto;
        }).collect(Collectors.toList());
    }

    private BpProductionFacilityTypeDto convertType(BpProductionFacilityType e) {
        BpProductionFacilityTypeDto dto = new BpProductionFacilityTypeDto();
        BeanUtils.copyProperties(e, dto);
        String remindUserIdJson = e.getRemindUserIdJson();
        if (remindUserIdJson != null) {
            List<Long> userIds = JSON.parseArray(remindUserIdJson, Long.class);
            List<BaseUser> users = baseUserDao.findAllById(userIds);
            List<EduCertEditUserNameBean> userList = users.stream().map(EduCertEditUserNameBean::new).collect(Collectors.toList());
            dto.setRemindUserIds(userIds);
            dto.setUserNames(userList);
        }
        Long departId = e.getDepartId();
        if (departId != null) {
            BpDepart depart = bpDepartDao.getOne(departId);
            dto.setDepartName(new EduCertEditUserNameBean(departId, depart == null ? "" : depart.getName()));
        }
        return dto;
    }

    @Override
    public BpProductionFacilityType add(BpProductionFacilityTypeBean bean) {
        int count = dao.countByName(bean.getName());
        if (count > 0) {
            throw new IllegalArgumentException("设备装置类型名称已存在");
        }
        //提醒类型
        judgeRemindType(bean);
        BpProductionFacilityType type = new BpProductionFacilityType();
        BeanUtils.copyProperties(bean, type);
        type.setRemindUserIdJson(CollectionUtils.isEmpty(bean.getRemindUserIds()) ? null : JSON.toJSONString(bean.getRemindUserIds()));
        return dao.save(type);
    }

    private void judgeRemindType(BpProductionFacilityTypeBean bean) {
        if (bean.getExpireRemindOrNot() == 1) {
//            Assert.isTrue(CertificateRemindTypes.hasType(bean.getRemindType()), "不支持此提醒类型");
//            Assert.notNull(bean.getRemindTime(), "提醒时间不能为空");
            Assert.notNull(bean.getUserDepartFlag(), "userDepartFlag cannot be null");
            if (bean.getUserDepartFlag() == 0) {
                Assert.isTrue(!CollectionUtils.isEmpty(bean.getRemindUserIds()), "请选择提醒对象");
            } else {
                Assert.notNull(bean.getDepartId(), "请选择提醒对象");
            }
        }
    }

    @Override
    public void edit(BpProductionFacilityTypeBean bean) {
        int count = dao.countByName(bean.getName());
        if (count > 1) {
            throw new IllegalArgumentException("设备装置类型名称已存在");
        }
        judgeRemindType(bean);
        Byte newRemind = bean.getExpireRemindOrNot();
        BpProductionFacilityType type = dao.findById(bean.getId()).get();
        Byte oldRemind = type.getExpireRemindOrNot();
        BeanUtils.copyProperties(bean, type);
        type.setRemindUserIdJson(CollectionUtils.isEmpty(bean.getRemindUserIds()) ? null : JSON.toJSONString(bean.getRemindUserIds()));
        dao.save(type);
        //修改只基于是否提醒做两种情况: 是->否 和 否->是 ; 同一提醒类型下的变动不做
        if (!newRemind.equals(oldRemind)) {
            List<BpProductionFacility> list = facilityDao.findByType(bean.getId());
            if (CollectionUtils.isEmpty(list)) {
                return;
            }
            //改为不提醒: 移除尚未提醒的
            if (newRemind == 0) {
                for (BpProductionFacility facility : list) {
                    facilityService.removeNotify(facility.getId());
                }
            }
            //改为提醒: 移除先前,新增通知
            else {
                for (BpProductionFacility facility : list) {
                    facilityService.removeNotify(facility.getId());
                    Long typeId = facility.getType();
                    Date validityDate = facility.getValidityDate();
                    if (typeId != null && validityDate != null) {
                        facilityService.notify(facility.getName(), facility.getId(), typeId, validityDate);
                    }
                }
            }
        }
    }

    @Override
    public BpProductionFacilityTypeDto getById(Long id) {
        return convertType(dao.getOne(id));
    }

    @Override
    public void delete(Long id) {
        Long count = dao.countByParentId(id);
        Assert.isTrue(count == 0, "该类型下面有类型，请先删除子类型");
        dao.deleteById(id);
        facilityDao.resetTypeId(id);
    }

    @Override
    public List<BpTypeBean> getPage() {
        List<BpProductionFacilityType> all = dao.findAll();
        ArrayList<BpTypeBean> list = new ArrayList<>();
        for (BpProductionFacilityType b : all) {
            BpTypeBean t = new BpTypeBean();
            t.setLabel(b.getName());
            t.setValue(b.getId());
            list.add(t);
        }
        return list;
    }

    @Override
    public List<Long> findChildrenIdList(Long parentId) {
        List<BpProductionFacilityType> list = dao.findAll();
        if (parentId == null || parentId == 0) {
            return list.stream().map(BpProductionFacilityType::getId).collect(Collectors.toList());
        }
        List<Long> result = new ArrayList<>();
        Map<Long, BpProductionFacilityType> map = list.stream()
                .collect(Collectors.toMap(BpProductionFacilityType::getId, Function.identity()));
        for (BpProductionFacilityType type : list) {
            if (isChildType(parentId, type, map)) {
                result.add(type.getId());
            }
        }
        return result;
    }

    @Override
    public List<BpProductionFacilityType> findList(String companyCode) {
        return dao.findList(companyCode);
    }

    private boolean isChildType(Long parentId, BpProductionFacilityType type, Map<Long, BpProductionFacilityType> map) {
        if (type.getParentId() == null) {
            return false;
        }
        if (parentId.equals(type.getParentId())) {
            return true;
        }
        BpProductionFacilityType parent = map.get(type.getParentId());
        if (parent == null) {
            return false;
        }
        return isChildType(parentId, parent, map);
    }
}
